package com.lixueju.security.box.web.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lixueju.security.box.core.dto.ResultData;
import com.lixueju.security.box.core.enums.ResultDataEnum;
import com.lixueju.security.box.core.enums.TableFieldEnum;
import com.lixueju.security.box.core.exception.SecurityBoxException;
import com.lixueju.security.box.core.model.AuthMenu;
import com.lixueju.security.box.web.mapper.AuthMenuMapper;
import com.lixueju.security.box.core.model.AuthRoleMenuRel;
import com.lixueju.security.box.web.service.IAuthMenuService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lixueju.security.box.web.service.IAuthRoleMenuRelService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 储存菜单信息 服务实现类
 * </p>
 *
 * @author lixueju
 * @since 2019-11-13
 */
@Service
public class AuthMenuServiceImpl extends ServiceImpl<AuthMenuMapper, AuthMenu> implements IAuthMenuService {
    @Autowired
    private AuthMenuMapper authMenuMapper;

    @Autowired
    private IAuthRoleMenuRelService authRoleMenuRelService;

    @Override
    public List<AuthMenu> queryAllMenuByUserId(Long userId) {
        List<AuthMenu> authMenuList = null;
        // 系统管理员ID固定为10000
        if (userId == 10000L) {
            authMenuList = selectAllAdminMenu(false);
        } else {
            authMenuList = authMenuMapper.queryAuthMenuListByUserId(userId, TableFieldEnum.AuthMenuOfType.menu.code());
        }
        Map<Long, List<AuthMenu>> childrenMenuListMap = authMenuList.stream().collect(Collectors.groupingBy(AuthMenu::getParentId));
        List<AuthMenu> adminList = childrenMenuListMap.get(0L);
        if (adminList == null || adminList.size() < 1) {
            throw new SecurityBoxException(new ResultData(ResultDataEnum.AUTH_NO_AUTHORITY.code(),ResultDataEnum.AUTH_NO_AUTHORITY.desc(),null));
        }
        for (AuthMenu adminMenu : adminList) {
            List<AuthMenu> oneList = childrenMenuListMap.get(adminMenu.getId());
            if (oneList == null || oneList.size() < 1) {
                continue;
            }
            oneList.sort((o1, o2) -> o1.getOrderNum().compareTo(o2.getOrderNum()));
            adminMenu.getExtend().put("children", oneList);
            for (AuthMenu oneMenu : oneList) {
                // 封装二级菜单
                List<AuthMenu> towList = childrenMenuListMap.get(oneMenu.getId());
                if (towList == null || towList.size() < 1) {
                    continue;
                }
                oneMenu.getExtend().put("children", towList);
                towList.sort((o1, o2) -> o1.getOrderNum().compareTo(o2.getOrderNum()));
            }
        }
        return adminList;
    }


    @Override
    public IPage<AuthMenu> selectMenuPage(Page<AuthMenu> page, AuthMenu authMenu) {
        QueryWrapper<AuthMenu> quAdminMenu = new QueryWrapper<>();
        quAdminMenu.eq("systemType", TableFieldEnum.AuthMenuOfSystemType.admin.code());
        quAdminMenu.eq("parentId", 0L);
        AuthMenu adminMenu = this.getOne(quAdminMenu);
        if (adminMenu == null) {
            throw new SecurityBoxException("后台系统菜单不存在");
        }
        List<AuthMenu> allMenuList = selectAllAdminMenu(true);
        Map<Long, List<AuthMenu>> childrenMenuListMap = allMenuList.stream().collect(Collectors.groupingBy(AuthMenu::getParentId));
        QueryWrapper<AuthMenu> queryAuthMenu = new QueryWrapper<>();
        queryAuthMenu.eq("delFlag", TableFieldEnum.AllOfdelFlag.no.code());
        queryAuthMenu.eq("systemType", TableFieldEnum.AuthMenuOfSystemType.admin.code());
        if (!StringUtils.isBlank(authMenu.getName())) {
            queryAuthMenu.like("name", authMenu.getName());
        }
        queryAuthMenu.eq("parentId", adminMenu.getId());
        queryAuthMenu.eq("type", TableFieldEnum.AuthMenuOfType.menu.code());
        queryAuthMenu.orderByAsc("orderNum");
        IPage<AuthMenu> authMenuPage = this.page(page, queryAuthMenu);
        List<AuthMenu> oneMenus = authMenuPage.getRecords();
        for (AuthMenu oneMenu : oneMenus) {
            List<AuthMenu> towMenuAndOperationList = childrenMenuListMap.get(oneMenu.getId());
            List<AuthMenu> towMenuList = new ArrayList<>();
            List<AuthMenu> towOperationList = new ArrayList<>();
            if (towMenuAndOperationList != null) {
                for (AuthMenu towMenuAndOperation : towMenuAndOperationList) {
                    if (towMenuAndOperation.getType().equals(TableFieldEnum.AuthMenuOfType.menu.code())) {
                        towMenuList.add(towMenuAndOperation);
                        List<AuthMenu> operationMenuList = childrenMenuListMap.get(towMenuAndOperation.getId());
                        if (operationMenuList == null) {
                            operationMenuList = new ArrayList<>();
                        }
                        towMenuAndOperation.getExtend().put("operationChildren", operationMenuList);
                    } else if (towMenuAndOperation.getType().equals(TableFieldEnum.AuthMenuOfType.operation.code())) {
                        towOperationList.add(towMenuAndOperation);
                    }
                }
            }
            oneMenu.getExtend().put("operationChildren", towOperationList);
            oneMenu.getExtend().put("children", towMenuList);
        }
        return authMenuPage;
    }

    /**
     * 查询系统后台所有菜单
     *
     * @param hasOperation 是否查询操作菜单
     */
    private List<AuthMenu> selectAllAdminMenu(boolean hasOperation) {
        QueryWrapper<AuthMenu> quAllMenu = new QueryWrapper<>();
        quAllMenu.eq("delFlag", TableFieldEnum.AllOfdelFlag.no.code());
        quAllMenu.eq("systemType", TableFieldEnum.AuthMenuOfSystemType.admin.code());
        if (!hasOperation) {
            quAllMenu.eq("type", TableFieldEnum.AuthMenuOfType.menu.code());
        }
        return this.list(quAllMenu);
    }

    @Override
    public Boolean addOrUpdateAuthMenu(AuthMenu authMenu) {
        verifyAuthMenu(authMenu);
        return this.saveOrUpdate(authMenu);
    }

    @Override
    public Boolean deleteAuthMenu(AuthMenu authMenu) {
        if (authMenu.getId() == null) {
            throw new SecurityBoxException("参数id不可为空");
        }
        QueryWrapper<AuthRoleMenuRel> delAuthRoleMenuRel = new QueryWrapper<>();
        delAuthRoleMenuRel.eq("menuId", authMenu.getId());
        authRoleMenuRelService.remove(delAuthRoleMenuRel);
        List<AuthMenu> deleteAuthMenuList = getAuthMenuListByParentId(null, authMenu.getId());
        Set<Long> deleteIds = new HashSet<>();
        deleteIds.add(authMenu.getId());
        if (deleteAuthMenuList.size() > 0) {
            deleteIds.addAll(deleteAuthMenuList.stream().collect(Collectors.toMap(AuthMenu::getId, a -> a)).keySet());
        }
        return this.removeByIds(deleteIds);
    }

    private List<AuthMenu> getAuthMenuListByParentId(List<AuthMenu> authMenuList, Object... parentIds) {
        if (authMenuList == null) {
            authMenuList = new ArrayList<>();
        }
        QueryWrapper<AuthMenu> quAuthMenu = new QueryWrapper<>();
        quAuthMenu.in("parentId", parentIds);
        List<AuthMenu> list = this.list(quAuthMenu);
        if (list == null || list.size() < 1) {
            return authMenuList;
        }
        authMenuList.addAll(list);
        Object[] Ids = list.stream().collect(Collectors.toMap(AuthMenu::getId, a -> a)).keySet().toArray();
        return getAuthMenuListByParentId(authMenuList, Ids);
    }

    @Override
    public List<AuthMenu> getAuthMenuListByChildrenIds(List<AuthMenu> authMenuList, Set<Long> childrenIds) {
        if (authMenuList == null) {
            authMenuList = new ArrayList<>();
        }
        if (CollectionUtils.isEmpty(childrenIds)) {

            return removeRepeatOfId(authMenuList);
        }
        Collection<AuthMenu> list = this.listByIds(childrenIds);
        if (CollectionUtils.isEmpty(list)) {
            return removeRepeatOfId(authMenuList);
        }
        authMenuList.addAll(list);
        Set<Long> IdSet = list.stream().filter(menu -> !menu.getParentId().equals(0L)).collect(Collectors.groupingBy(AuthMenu::getParentId)).keySet();
        return getAuthMenuListByChildrenIds(authMenuList, IdSet);
    }

    private List<AuthMenu> removeRepeatOfId(List<AuthMenu> authMenuList) {
        if (CollectionUtils.isEmpty(authMenuList)) {
            return authMenuList;
        }
        return authMenuList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(authMenu -> authMenu.getId()))), ArrayList::new));
    }


    @Override
    public Set<String> queryAllPermissionByUserId(Long userId) {
        Set<String> authMenuList = null;
        // 系统管理员ID固定为10000
        if (userId == 10000L) {
            authMenuList = authMenuMapper.queryAllPermission();
        } else {
            authMenuList = authMenuMapper.queryAllPermissionByUserId(userId);
        }
        return authMenuList;
    }

    @Override
    public JSONArray menuTree() {
        JSONArray result = new JSONArray();
        QueryWrapper<AuthMenu> quAllMenu = new QueryWrapper<>();
        quAllMenu.eq("delFlag", TableFieldEnum.AllOfdelFlag.no.code());
        quAllMenu.eq("type", TableFieldEnum.AuthMenuOfType.menu.code());
        quAllMenu.orderByAsc("orderNum");
        List<AuthMenu> allList = this.list(quAllMenu);
        Map<Long, List<AuthMenu>> childrenMenuListMap = allList.stream().collect(Collectors.groupingBy(AuthMenu::getParentId));
        List<AuthMenu> topAuthMenuList = childrenMenuListMap.get(0L);
        for (AuthMenu topAuthMenu : topAuthMenuList) {
            JSONObject top = new JSONObject();
            top.put("id", topAuthMenu.getId());
            top.put("name", topAuthMenu.getName());
            top.put("icon", topAuthMenu.getIcon());
            top.put("group", true);
            top.put("parentId", topAuthMenu.getParentId());
            List<AuthMenu> oneMenuList = childrenMenuListMap.get(topAuthMenu.getId());
            if (oneMenuList == null) {
                continue;
            }
            JSONArray oneMenuResult = new JSONArray();
            for (AuthMenu oneMenu : oneMenuList) {
                JSONObject one = new JSONObject();
                one.put("id", oneMenu.getId());
                one.put("icon", oneMenu.getIcon());
                one.put("name", oneMenu.getName());
                one.put("parentId", oneMenu.getParentId());
                List<AuthMenu> twoMenuList = childrenMenuListMap.get(oneMenu.getId());
                if (twoMenuList != null) {
                    JSONArray twoMenuResult = new JSONArray();
                    for (AuthMenu twoMenu : twoMenuList) {
                        JSONObject two = new JSONObject();
                        two.put("id", twoMenu.getId());
                        two.put("icon", twoMenu.getIcon());
                        two.put("name", twoMenu.getName());
                        two.put("parentId", twoMenu.getParentId());
                        twoMenuResult.add(two);
                    }
                    one.put("children", twoMenuResult);
                }
                oneMenuResult.add(one);
            }
            top.put("children", oneMenuResult);
            result.add(top);
        }
        //顶级选项
        JSONObject notParent = new JSONObject();
        notParent.put("id", 0);
        notParent.put("name", "新增系统");
        result.add(notParent);
        return result;
    }

    @Override
    public JSONArray menuTreeForPermission() {
        QueryWrapper<AuthMenu> quAllMenu = new QueryWrapper<>();
        quAllMenu.eq("delFlag", TableFieldEnum.AllOfdelFlag.no.code());
        quAllMenu.eq("type", TableFieldEnum.AuthMenuOfType.operation.code());
        Map<Long, List<AuthMenu>> operationMap = this.list(quAllMenu).stream().collect(Collectors.groupingBy(AuthMenu::getParentId));
        JSONArray menuTreeArray = menuTree();
        return setAllOperation(menuTreeArray, operationMap);
    }

    private JSONArray setAllOperation(JSONArray menuTreeArray, Map<Long, List<AuthMenu>> operationMap) {
        Object remove = null;
        for (Object o : menuTreeArray) {
            JSONObject menu = (JSONObject) o;
            if (menu.getLongValue("id") == 0) {
                remove = o;
            }
            if (menu.get("children") != null) {
                this.setAllOperation(menu.getJSONArray("children"), operationMap);
            }
            List<AuthMenu> operationList = operationMap.get(menu.getLong("id"));
            if (operationList == null || operationList.size() < 1) {
                continue;
            }
            JSONArray operations = new JSONArray();
            for (AuthMenu authMenu : operationList) {
                JSONObject operationJson = new JSONObject();
                operationJson.put("id", authMenu.getId());
                operationJson.put("description", authMenu.getName());
                operationJson.put("parentId", authMenu.getParentId());
                // ...
                operations.add(operationJson);
            }
            menu.put("operations", operations);
        }
        if (remove != null) {
            menuTreeArray.remove(remove);
        }
        return menuTreeArray;
    }

    private void verifyAuthMenu(AuthMenu authMenu) {
        if (StringUtils.isBlank(authMenu.getName())) {
            throw new SecurityBoxException("菜单名称不能为空");
        }
        JSONArray parentIds = authMenu.getExtend().getJSONArray("parentIds");
        if (parentIds == null || parentIds.size() < 1) {
            throw new SecurityBoxException("上级菜单不能为空");
        }
        Long topId = Long.parseLong(String.valueOf(parentIds.get(0)));
        AuthMenu topMenu = this.getById(topId);
        if (topMenu == null) {
            throw new SecurityBoxException("找不到该菜单所属系统");
        }
        authMenu.setSystemType(topMenu.getSystemType());
        Long parentId = Long.parseLong(String.valueOf(parentIds.get(parentIds.size() - 1)));
        authMenu.setParentId(parentId);
    }
}
